package com.kamistoat.meimeichat.meimeichatserverapplication.netty.handlers;

import com.alibaba.fastjson.JSON;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.NettyServerBizHandler;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.service.NettyUserService;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.utils.NettyConstants;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.utils.NettySocketChannelUtil;
import com.kamistoat.meimeichatserveraggrement.protocol.msg.MsgGroupRequest;
import com.kamistoat.meimeichatserveraggrement.protocol.msg.MsgGroupResponse;
import com.kamistoat.meimeichatserveraggrement.protocol.talk.TalkNoticeResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.group.ChannelGroup;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;

/**
 * 群聊天Handler。向群组中所有在线用户发送消息. 要注意用户可能没有展开聊天框的情况
 */
@Component
@ChannelHandler.Sharable
public class MsgGroupHandlerServer extends NettyServerBizHandler<MsgGroupRequest> {
    @Autowired
    NettyUserService nettyUserService;

    /**
     * @param channel
     * @param msgGroupRequest
     * @Warning:子类只需要重写该方法
     */
    @Override
    public void channelRead(Channel channel, MsgGroupRequest msgGroupRequest) {
        if (msgGroupRequest == null) return;
        logger.info("群聊消息请求处理: " + JSON.toJSONString(msgGroupRequest));
        // 获取群组通信管道
        ChannelGroup cur_group_channelGroup = NettySocketChannelUtil.getChannelGroup(msgGroupRequest.getTalkId());

        // 若为null，则说明当前群组没有任何其他成员在线(成员下线会从群组channel中删除自身，当最后一个成员下线时同时删除群组channel)，当前用户为唯一在线成员。
        // 则先创建群组channel并添加自身
        if (cur_group_channelGroup == null) {
            NettySocketChannelUtil.addChannelGroup(msgGroupRequest.getTalkId(), channel);
            cur_group_channelGroup = NettySocketChannelUtil.getChannelGroup(msgGroupRequest.getTalkId());
        }

        // 这里用了异步去完成聊天消息入库。在后面继续发送时并不查询该异步是否执行成功
        // 换句话说，能保证在线用户一定能收到消息，但是不能保证离线用户上线时能否找到之前的聊天记录
        CompletableFuture<Void> asyncAppendChatRecord = nettyUserService.asyncAppendChatRecord(
                msgGroupRequest.getUserId(),
                msgGroupRequest.getTalkId(),
                msgGroupRequest.getMsgText(),
                msgGroupRequest.getMsgDate(),
                msgGroupRequest.getMsgType(),
                NettyConstants.TalkType.Group.getCode()
        );
        // 不需要拉起自己-群组对话框，因为保证一定在发送消息前创建了对话框
        // 但是需要检查群组-好友对话框是否拉起，如果没有拉起则拉起对话框。一种保证一致性的做法是，总是认为没有拉起，于是总是向对方发送拉起响应


        // 获取群组channel，向所有在线的群成员转发消息
        MsgGroupResponse msgGroupResponse = new MsgGroupResponse();
        BeanUtils.copyProperties(msgGroupRequest, msgGroupResponse);
        cur_group_channelGroup.writeAndFlush(msgGroupResponse);
    }
}
